package yagoMarried;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import dataset.DataEntry;
import dataset.Dataset;

import edu.stanford.nlp.ie.AbstractSequenceClassifier;
import edu.stanford.nlp.ie.crf.CRFClassifier;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.ling.CoreAnnotations.LemmaAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.PartOfSpeechAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.SentencesAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.TextAnnotation;
import edu.stanford.nlp.ling.CoreAnnotations.TokensAnnotation;
import edu.stanford.nlp.pipeline.Annotation;
import edu.stanford.nlp.pipeline.StanfordCoreNLP;
import edu.stanford.nlp.util.CoreMap;

import triples.Triple;
import triples.TripleWraper;
import triples.TriplesProcessor;

public class DataFromYAGO {
	
	ArrayList<YagoEntity> yagoList;
	ArrayList<TripleWraper> triples;
	StanfordCoreNLP pipeline;
	
	public DataFromYAGO(){
		this.initial();
	}
	
	public void initial(){
		ExtractYago ey = new ExtractYago();
		this.yagoList = ey.getIndexedEntities();
		System.out.println("get all indexed entities");
		String serializedClassifier = "/largedata1/cmput696/students/lyao1/yago2temp/TempYago/lib/classifiers/english.muc.7class.distsim.crf.ser.gz";
	    AbstractSequenceClassifier<CoreLabel> classifier = CRFClassifier.getClassifierNoExceptions(serializedClassifier);
	    TriplesProcessor tp = new TriplesProcessor(classifier,"/largedata1/cmput696/students/lyao1/sogodata/2data/result/tripple",null);
		tp.get_triple_list();
		tp.recoverAndtagTimes();
		System.out.println("get tagged triples");
		//this.triples = tp.getYagoTripleWrapers("/largedata1/cmput696/students/lyao1/sogodata/2data/texts/");
		this.triples = tp.getYagoTripleWrapers_cached("/largedata1/cmput696/students/lyao1/sogodata/2data/texts/", "/largedata1/cmput696/students/lyao1/sogodata/2data/map.txt");
		System.out.println("yagolist size:"+this.yagoList.size());
		//System.out.println(this.yagoList.get(0).getArg1());
		System.out.println("tripleMap size:"+this.triples.size());
		//System.out.println(this.triples.get(0).yname+","+this.triples.get(0).tri.getE1()+","+this.triples.get(0).tri.getE2());
		
		
		//initial open NLP
		Properties props = new Properties();
		props.put("annotators", "tokenize, ssplit, pos");
		this.pipeline = new StanfordCoreNLP(props);
		
	}
	
	//see whether one triple and one yago entities map
	//if map, generate a data entry,
	//if not return null;
	public boolean OneTripleOneYago(Triple tri, YagoEntity ye){
		
		ArrayList<String> tri_dates = tri.extractDate();
		if( tri_dates.size()==0 ){
			System.out.println("!!!!this is not supposed to appper,no date extracted from triple");
		}else{
			//find match date and match entity ,then is a match
			for(String date:tri_dates){
				boolean match=false;
				boolean dateMatch = false;
				//System.out.println("\t\tTridates:"+date+",match begin:"+Match.playsForDateMatch(date, ye.getTimebegin()) +",match end:"+Match.playsForDateMatch(date,ye.getTimeend() ));
				dateMatch = Match.playsForDateMatch(date, ye.getTimebegin())||Match.playsForDateMatch(date, ye.getTimeend());
				//if(dateMatch ){
					//#NEXT TEST HOW MANY ENTITIS MAP NO MATHER WHETHER DATE MATCHES 
					String t_e1 = tri.get_s_e1();
					String t_e2 = tri.get_s_e2();
					String arg2 = ye.getArg2();
					boolean e_Match = false;
				//	System.out.println("\t\tArg2:"+arg2+",tri_e1:"+t_e1+",match:"+Match.playsForEntityMatch(t_e1, arg2)+",tri+e2:"+t_e2+",match:"+Match.playsForEntityMatch(t_e2, arg2));
					e_Match = Match.playsForEntityMatch(t_e1, arg2)||Match.playsForEntityMatch(t_e2, arg2);
					
					if( e_Match&&dateMatch){
					//	System.out.println("\t\t^^^^ time  match but entity don't  Match");
					//	System.out.println()
						System.out.println("triple:");
						System.out.println("\tSEN:"+tri.getSentence());
						System.out.println("\tNEWS:"+tri.getNew_sentence());
						System.out.println("matched YAGO entities:");
						System.out.println("\t\tTridates:"+date+",match begin:"+Match.playsForDateMatch(date, ye.getTimebegin()) +",match end:"+Match.playsForDateMatch(date,ye.getTimeend() ));
						System.out.println("\t\tArg2:"+arg2+",tri_e1:"+t_e1+",match:"+Match.playsForEntityMatch(t_e1, arg2)+",tri+e2:"+t_e2+",match:"+Match.playsForEntityMatch(t_e2, arg2));
					}
					
					
					return e_Match&&dateMatch;
				//}
				
				//return Match.playsForDateMatch(date, ye.getTimebegin())||Match.playsForDateMatch(date, ye.getTimeend());
				//return false;
			}
		}
		return false;
	}
	
	public boolean tripleYagoEntityMatch(TripleWraper tw, YagoEntity ye){
		Triple tri = tw.tri;
		String yname = tw.yname;
		String t_e1 = tri.get_s_e1();
		String t_e2 = tri.get_s_e2();
		String arg2 = ye.getArg2();
		String arg1 = ye.getArg1();
		
		if( IndexTACReader.convert(arg1).equals(yname)){
		
			return Match.playsForEntityMatch(t_e1, arg2)||Match.playsForEntityMatch(t_e2, arg2);
		}else{
			if( IndexTACReader.convert(arg2).equals(yname)){
				return Match.playsForEntityMatch(t_e1, arg1)||Match.playsForEntityMatch(t_e2, arg1);
			}
			System.out.println("both args not match yname!");
			return false;
		}
	}
	public boolean dateYageEntityMatch(String date,YagoEntity ye){
		if( ye.getTimebegin()==null&&ye.getTimeend()==null){
			System.out.println("no time information for ye");
			return false;
		}
		if( ye.getTimeend()==null){
			return Match.playsForDateMatch(date, ye.getTimebegin());
		}
		
		if( ye.getTimebegin()==null){
			return Match.playsForDateMatch(date, ye.getTimeend());
		}
		
		return Match.playsForDateMatch(date, ye.getTimebegin())||Match.playsForDateMatch(date, ye.getTimeend());
	}
	
	//if the triple is positive,return entry, else return 
	public DataEntry genDataEntryForOneTriple(TripleWraper tw){
		
		ArrayList<YagoEntity> matchYes = this.findye(tw);
		if( (matchYes==null)||(matchYes.size()==0) ){
			System.out.println("no match Yes");
			return null;
			
		}
		//System.out.println("has match Yes:"+matchYes.size());
		
		ArrayList<YagoEntity> eMatches = new ArrayList<YagoEntity>();
		for(YagoEntity ye: matchYes){
			
		//	System.out.println("\t-------");
		//	System.out.println("\targ1:"+ye.getArg1());
		//	System.out.println("\targ2:"+ye.getArg2());
		//	System.out.println("\ttimebegin:"+ye.getTimebegin());
		//	System.out.println("\timeend:"+ye.getTimeend());
			
			//first see whether there is the same entity
			//collect all the entites that has the same entity
			
			if( this.tripleYagoEntityMatch(tw, ye)){
				eMatches.add(ye);
			}
			
		}
		if(eMatches.size()==0){
			return null;
		}
		
		//for each date in triple, found
		ArrayList<String>tri_dates = tw.tri.extractDate();
		ArrayList<String>related = new ArrayList<String>();
		
		for(String date:tri_dates){
			boolean found_match=false;
			for(YagoEntity ye: eMatches){
				if( this.dateYageEntityMatch(date, ye)){
					found_match = true;
					break;
				}
				
			}
			if( found_match==false){
				return null;
			}
		}
		
		for(int i=0;i<tri_dates.size();i++){
			related.add("REL");
		}
		return new DataEntry(tw.tri,tw.tri.extractRelation(),tri_dates,related);
		
	}
	
	//if the triple is positive,return entry, else return null,
	//and the triple must also contain the word 'married'
	public DataEntry genDataEntryForOneTriple_strict(TripleWraper tw){
		
		ArrayList<YagoEntity> matchYes = this.findye(tw);
		if( (matchYes==null)||(matchYes.size()==0) ){
			System.out.println("no match Yes");
			return null;
			
		}
		//System.out.println("has match Yes:"+matchYes.size());
		
		ArrayList<YagoEntity> eMatches = new ArrayList<YagoEntity>();
		for(YagoEntity ye: matchYes){
			
		//	System.out.println("\t-------");
		//	System.out.println("\targ1:"+ye.getArg1());
		//	System.out.println("\targ2:"+ye.getArg2());
		//	System.out.println("\ttimebegin:"+ye.getTimebegin());
		//	System.out.println("\timeend:"+ye.getTimeend());
			
			//first see whether there is the same entity
			//collect all the entites that has the same entity
			
			if( this.tripleYagoEntityMatch(tw, ye)){
				eMatches.add(ye);
			}
			
		}
		if(eMatches.size()==0){
			return null;
		}
		
		//for each date in triple, found
		ArrayList<String>tri_dates = tw.tri.extractDate();
		ArrayList<String>related = new ArrayList<String>();
		
		for(String date:tri_dates){
			boolean found_match=false;
			for(YagoEntity ye: eMatches){
				if( this.dateYageEntityMatch(date, ye)){
					found_match = true;
					break;
				}
				
			}
			if( found_match==false){
				return null;
			}
		}
		
		for(int i=0;i<tri_dates.size();i++){
			related.add("REL");
		}
		
		String tri_relation = tw.tri.extractRelation();
		if( this.containVerb(tri_relation)==false){
			return null;
		}
		
		return new DataEntry(tw.tri,tw.tri.extractRelation(),tri_dates,related);
		
	}
	
	
	public boolean containVerb(String relation){
		Annotation document = new Annotation(relation);
	    pipeline.annotate(document);
	    List<CoreMap> sentences = document.get(SentencesAnnotation.class);

	    for(CoreMap sentence: sentences) {
	      
	        for (CoreLabel token: sentence.get(TokensAnnotation.class)) {
	          // this is the text of the token
	          //String word = token.get(TextAnnotation.class);
	          // this is the POS tag of the token
	          String pos = token.get(PartOfSpeechAnnotation.class);
	      
	          //String lemma = token.get(LemmaAnnotation.class);
	          
	          //System.out.println("word:"+word+",lemma:"+lemma+",pos:"+pos);
	          if( pos.indexOf("VB")>-1){
	        	  return true;
	          }
	         
	        }
	    }
	    return false;
	}
	
	public Dataset genDataSet(){
		ArrayList<DataEntry> ds = new ArrayList<DataEntry>();
		int cc=0;
		int oc=0;
		for(TripleWraper tw:this.triples){
			//DataEntry de = this.genDataEntryForOneTriple(tw);
			DataEntry de = this.genDataEntryForOneTriple_strict(tw);
			if( de!=null){
				ds.add(de);

				cc++;
				System.out.println("gen entries:cc"+cc+",total triples:"+this.triples.size());
			}
			oc++;
			System.out.println("current gendata triple:"+oc+"/"+this.triples.size());
		}
		System.out.println("dataset size:"+ds.size());
		return new Dataset(ds);
	}
	
	public void multple(){
		int c=0;
		int date_match_c=0;
		for(TripleWraper tw:this.triples){
			ArrayList<YagoEntity> matchYes = this.findye(tw);
			//System.out.println("triple:");
			//System.out.println("\tSEN:"+tw.tri.getSentence());
			//System.out.println("\tNEWS:"+tw.tri.getNew_sentence());
			//System.out.println("YAGO entities:");
			if( matchYes.size()>0){
				c++;
			}
			
		
			for(YagoEntity ye: matchYes){
				
				//System.out.println("\t-------");
				//System.out.println("\targ1:"+ye.getArg1());
				//System.out.println("\targ2:"+ye.getArg2());
				//System.out.println("\ttimebegin:"+ye.getTimebegin());
				//System.out.println("\timeend:"+ye.getTimeend());
				
				if( this.OneTripleOneYago(tw.tri, ye) ){
					
					date_match_c++;
				}
				
				
			}
			System.out.println("************");
			
		}
		System.out.println("triples:"+this.triples.size()+", found enetities:"+c);
		System.out.println("date match triples:"+date_match_c);
	}
	//find corresponding yago entities for each triple wraper
	public ArrayList<YagoEntity> findye(TripleWraper tw){
		ArrayList<YagoEntity> res = new ArrayList<YagoEntity>();
		String name = tw.yname;
		for( YagoEntity ye: this.yagoList){
			String p2 = IndexTACReader.convert(ye.getArg1());
			//System.out.println("p2:"+p2+",name:"+name);
			
			if(p2.equals(name)){
				res.add(ye);
			}else{
				String p3 = IndexTACReader.convert(ye.getArg2());
				//System.out.println("p3:"+p3+",name:"+name);
				if( p3.equals(name)){
					res.add(ye);
				}
			}
		}
		return res;
	}
	

	public static void main(String[]args){
		
		DataFromYAGO dfy = new DataFromYAGO();
		//dfy.multple();
		Dataset ds = dfy.genDataSet();
		ds.toText("/largedata1/cmput696/students/lyao1/sogodata/2data/dataset.txt");
		
	}
}
